package com.salinity.kun.helper;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.function.ToDoubleFunction;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;

import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

import com.salinity.kun.algorithm.FourierSeriesNotEqual;
import com.salinity.kun.algorithm.LinearEquation;
import com.salinity.kun.algorithm.SinInterpolation;
import com.salinity.kun.model.StationDateData;
import com.salinity.kun.model.FourierSeriesInput;
import com.salinity.kun.model.Point;
import com.salinity.kun.util.DateUtil;
import com.salinity.kun.util.PathUtil;
import com.salinity.kun.util.StringUtil;

public class BaseHydrologyDataHelper {

	public static List<StationDateData> getStationDateDataFromFile(Path filepath) throws IOException {

		return getStationDateDataFromFile(filepath, 1, 1, 2);
	}

	public static List<StationDateData> getStationDateDataFromFile(Path filepath, int dateColumn, int dataRow,
			int dataColumn) throws IOException {

		List<StationDateData> hydDataList = new ArrayList<>();
		try (BufferedReader br = Files.newBufferedReader(filepath)) {
			// skip first row
			String line = "";

			// 跳过非数据行
			while (dataRow > 0) {
				br.readLine();
				dataRow--;
			}
			String[] lineArray = null;
			while ((line = br.readLine()) != null) {
				lineArray = line.trim().split(",");
				hydDataList.add(new StationDateData(StringUtil.toUtf8(lineArray[0]), lineArray[dateColumn],
						Double.parseDouble(lineArray[dataColumn])));

			}
		}
		return hydDataList;
	}

	public static List<StationDateData> getTidesFromDB(String stationId, Date startDate, Date endDate) {

		OracleHelper oracleHelper = new OracleHelper();
		ResultSet rsltSet = null;
		List<StationDateData> hydDataList = null;
		try {
			oracleHelper.prepareTideSQL();

			rsltSet = oracleHelper.doTideQuery(startDate, endDate, stationId);
			hydDataList = oracleHelper.parseRslt(rsltSet);
			oracleHelper.end();
		} catch (SQLException e) {
			e.printStackTrace();
		}

		return hydDataList;

	}

	/**
	 * 
	 * 文件格式：
	 * 
	 * Date,2005/1/1 0:00:00 \n 330 \n 336 \n ...
	 * 
	 * 
	 * @param inputPath
	 * @param rawDeltaT
	 *            单位为分钟
	 * @param hours
	 * @return
	 * @throws ParseException
	 */
	public static List<StationDateData> getTidesFromFile(Path inputPath, Date sDate, int rawDeltaT, int hours)
			throws ParseException {
		List<StationDateData> rsltList = new ArrayList<>();
		String line = "";
		String[] strArr = null;
		Calendar calendar = Calendar.getInstance();
		SimpleDateFormat sdf = ConstantHelper.getDefaultFormat();
		Date startDate, endDate;
		try (BufferedReader br = Files.newBufferedReader(inputPath)) {

			strArr = br.readLine().trim().split(",");
			calendar.setTime(sdf.parse(strArr[1]));
			startDate = calendar.getTime();

			// 从指定日期开始读
			if (sDate != null) {
				while (calendar.getTime().compareTo(sDate) < 0) {
					br.readLine();
					calendar.add(Calendar.MINUTE, rawDeltaT);
				}
			}
			startDate = calendar.getTime();
			endDate = DateUtil.LDTime2Date(DateUtil.Date2LDTime(startDate).plusHours(hours + 1));
			while ((line = br.readLine()) != null && calendar.getTime().before(endDate)) {
				strArr = line.trim().split(",");
				rsltList.add(
						new StationDateData(null, sdf.format(calendar.getTime()), Double.valueOf(strArr[0]) / 100));
				calendar.add(Calendar.MINUTE, rawDeltaT);
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return rsltList;
	}

	public static List<StationDateData> getTidesFromFile(Path inputPath, Date sDate, int interval, int hours,
			int dataRow, int dateColumn, int dataColumn) throws ParseException, IOException {
		return getTidesFromFile(inputPath, sDate, interval, hours, dataRow, dateColumn, dataColumn, 0.0);
	}

	/**
	 * 依据开始和结束时间取数据
	 * 
	 * @param inputPath
	 * @param sDate
	 * @param eDate
	 * @param dateColumn
	 * @param dataRow
	 * @param dataColumn
	 * @param divNum
	 *            数据值的处理
	 * @return
	 * @throws ParseException
	 * @throws IOException
	 */
	public static List<StationDateData> getTidesFromFile(Path inputPath, Date sDate, Date eDate, int dateColumn,
			int dataRow, int dataColumn, double divNum) throws ParseException, IOException {
		String line = null;
		String strArr[] = null;
		SimpleDateFormat sdf = ConstantHelper.getDefaultFormat();
		Date startDate;
		List<StationDateData> rsltList = new ArrayList<>();
		double tempValue = 0.0;
		try (BufferedReader br = Files.newBufferedReader(inputPath)) {

			// 跳过非数据行
			while (dataRow > 0) {
				br.readLine();
				dataRow--;
			}
			strArr = br.readLine().trim().split(",");
			// 从指定日期开始读
			if (sDate != null) {
				while (sdf.parse(strArr[dateColumn]).compareTo(sDate) < 0) {

					String str = br.readLine();
					strArr = str.trim().split(",");
				}
			}

			startDate = sdf.parse(strArr[dateColumn]);

			// 记录第一条数据
			tempValue = divNum == 0.0 ? Double.valueOf(strArr[dataColumn]) : Double.valueOf(strArr[dataColumn]) / divNum;
			rsltList.add(new StationDateData(null, sdf.format(startDate),
					tempValue));
			while ((line = br.readLine()) != null && startDate.before(eDate)) {
				strArr = line.trim().split(",");
				startDate = sdf.parse(strArr[dateColumn]);
				tempValue = divNum == 0.0 ? Double.valueOf(strArr[dataColumn])
						: Double.valueOf(strArr[dataColumn]) / divNum;
				rsltList.add(new StationDateData(null, sdf.format(startDate),
						tempValue));
			}
		}
		return rsltList;
	}

	/**
	 * 读取StationDateData的存储文件
	 * 
	 * @param inputPath
	 * @param sDate
	 * @param interval
	 *            minutes
	 * @param hours
	 * @param dateColumn
	 * @param dataColumn
	 * @param divNum
	 *            如果是用厘米表示的，这个数字为100，cm/100 = m
	 * @return
	 * @throws ParseException
	 * @throws IOException
	 */
	public static List<StationDateData> getTidesFromFile(Path inputPath, Date sDate, int interval, int hours,
			int dateColumn, int dataRow, int dataColumn, double divNum) throws ParseException, IOException {
		String line = null;
		String strArr[] = null;
		SimpleDateFormat sdf = ConstantHelper.getDefaultFormat();
		Date startDate, endDate;
		List<StationDateData> rsltList = new ArrayList<>();
		try (BufferedReader br = Files.newBufferedReader(inputPath)) {

			// 跳过非数据行
			while (dataRow > 0) {
				br.readLine();
				dataRow--;
			}
			strArr = br.readLine().trim().split(",");
			// 从指定日期开始读
			if (sDate != null) {
				while (sdf.parse(strArr[dateColumn]).compareTo(sDate) < 0) {

					String str = br.readLine();
					strArr = str.trim().split(",");
				}
			}

			startDate = sdf.parse(strArr[dateColumn]);
			endDate = DateUtil.LDTime2Date(DateUtil.Date2LDTime(startDate).plusHours(hours + 1));

			// 记录第一条数据
			rsltList.add(new StationDateData(null, sdf.format(startDate),
					divNum == 0.0 ? Double.valueOf(strArr[dataColumn]) : Double.valueOf(strArr[dataColumn]) / divNum));
			while ((line = br.readLine()) != null && startDate.before(endDate)) {
				strArr = line.trim().split(",");
				startDate = sdf.parse(strArr[dateColumn]);
				rsltList.add(new StationDateData(null, sdf.format(startDate),
						divNum == 0.0 ? Double.valueOf(strArr[dataColumn])
								: Double.valueOf(strArr[dataColumn]) / divNum));
			}
		}
		return rsltList;
	}

	/**
	 * 取出时间间隔为 interval的数据，此数据必须存在，否则报错
	 * 
	 * @param dataList
	 * @param sDate
	 * @param interval
	 * @return
	 * @throws ParseException
	 */
	public static List<StationDateData> getDataByInterval(List<StationDateData> dataList, Date sDate, int interval)
			throws ParseException {

		int i = 0, count = 0;
		int len = dataList.size();
		List<StationDateData> rsltList = new ArrayList<>();
		SimpleDateFormat sdf = ConstantHelper.getDateFormat();
		Calendar calendar = DateUtil.Date2Calendar(sDate);
		while (!calendar.getTime().equals(sdf.parse(dataList.get(i).getDate()))) {
			i++;
		}

		for (; i < len; i++) {
			if (calendar.getTime().equals(sdf.parse(dataList.get(i).getDate()))) {
				rsltList.add(dataList.get(i).clone());
				calendar.add(Calendar.MINUTE, interval);
			} else {
				count++;
			}
		}
		System.out.println("剔除了 " + count + "条数据");
		return rsltList;

	}

	/**
	 * 
	 * 从抓取的文件中取整点数据的格式，间隔为一小时 文件格式： 2005/1/1 0:00:00,146\n 2005/1/1 0:00:00,146\n
	 * ...
	 * 
	 * @param inputPath
	 * @param sDate
	 * @param deltaT
	 *            minutes
	 * @param hours
	 * @return
	 * @throws IOException
	 * @throws ParseException
	 */
	public static List<StationDateData> getTidesFromFetchFile(Path inputPath, Date sDate, int deltaT, int hours)
			throws IOException, ParseException {
		return getTidesFromFile(inputPath, sDate, deltaT, hours, 0, 1, 100);

	}

	public static List<StationDateData> getTidesFromFile(Path inputPath, int rawDeltaT, int hours)
			throws ParseException {
		return getTidesFromFile(inputPath, null, rawDeltaT, hours);
	}

	public static void writeToFile(List<StationDateData> hydDataList, Path savePath) throws IOException {

		PathUtil.preparePath(savePath);

		// 默认保留两位小数
		DecimalFormat df = new DecimalFormat("#.000");
		try (BufferedWriter br = Files.newBufferedWriter(savePath, StandardCharsets.UTF_8, StandardOpenOption.WRITE)) {
			br.write("Station,Date,Hydro");
			br.newLine();
			for (StationDateData hydData : hydDataList) {
				br.write(hydData.getStationName() == null ? "*" : hydData.getStationName());
				br.write(",");
				br.write(hydData.getDate());
				br.write(",");
				br.write(df.format(hydData.getValue()));
				br.write(",");
				br.newLine();
			}
		}
	}

	
	
	/**
	 * 
	 * @param hydDataList
	 * @param startDate
	 * @param endDate
	 * @param dT
	 *            单位为 分钟
	 * @throws ParseException
	 */
	public static List<StationDateData> doLinearInterpolation(List<StationDateData> hydDataList, Date startDate,
			Date endDate, int dT) throws ParseException {
		if (startDate.compareTo(endDate) >= 0) {
			throw new RuntimeException("start date must be in front of end date.");
		}

		SimpleDateFormat sdf = ConstantHelper.getDefaultFormat();

		DecimalFormat df = new DecimalFormat("#.###");

		Date firstDate = sdf.parse(hydDataList.get(0).getDate());

		Date lastDate = sdf.parse(hydDataList.get(hydDataList.size() - 1).getDate());

		// 判断数据是否在所给的时间段内
		if (startDate.compareTo(lastDate) >= 0 || endDate.compareTo(firstDate) <= 0) {
			System.out.println("There is no data for the given time period.");
			return null;
		}

		// 提取出时间段内的数据
		List<StationDateData> tempHydDataList = new ArrayList<>();

		for (int i = 0; i < hydDataList.size(); i++) {
			StationDateData tempData = hydDataList.get(i);
			Date tempDate = sdf.parse(tempData.getDate());
			if (tempDate.compareTo(startDate) >= 0 && tempDate.compareTo(endDate) <= 0) {
				tempHydDataList.add(tempData);
			}
		}

		// 进行插值
		List<StationDateData> rsltHydList = new ArrayList<>();

		Calendar calendar = Calendar.getInstance();
		StationDateData tempFirstData = tempHydDataList.get(0);
		Date tempFirstDate = sdf.parse(tempFirstData.getDate());

		// 注意
		StationDateData tempLastData = tempHydDataList.get(tempHydDataList.size() - 1);
		Date tempLastDate = sdf.parse(tempLastData.getDate());
		int currentIndex = 0;

		// 设置起始时间
		calendar.setTime(startDate);
		//// 处理开头

		if (startDate.compareTo(tempFirstDate) < 0) {

			do {
				rsltHydList.add(new StationDateData(tempFirstData.getStationName(), sdf.format(calendar.getTime()),
						tempFirstData.getValue()));
				calendar.add(Calendar.MINUTE, dT);
			} while (calendar.getTime().compareTo(tempFirstDate) < 0);
		}

		// 处理中间
		StationDateData currentData, nextData;
		Date currentDate, nextDate;
		LinearEquation linearEquation;
		while (currentIndex + 1 < tempHydDataList.size()) {
			// 两两计算k,b;
			currentData = tempHydDataList.get(currentIndex);
			currentDate = sdf.parse(currentData.getDate());
			nextData = tempHydDataList.get(currentIndex + 1);
			nextDate = sdf.parse(nextData.getDate());

			Point p1 = new Point((double) currentDate.getTime(), currentData.getValue());
			Point p2 = new Point((double) nextDate.getTime(), nextData.getValue());
			linearEquation = new LinearEquation(p1, p2);

			while (calendar.getTime().compareTo(nextDate) < 0) {
				rsltHydList.add(new StationDateData(currentData.getStationName(), sdf.format(calendar.getTime()),
						Double.valueOf(df.format(linearEquation.getY(calendar.getTime().getTime())))));
				double a = Double.valueOf(df.format(linearEquation.getY(calendar.getTime().getTime())));
				// if (a > 10) {
				// System.out.println("start: " + sdf.format(currentDate.getTime()));
				// System.out.println("end: " + sdf.format(nextDate.getTime()));
				// System.out.printf("p1:%f,%f p2:%f,%f k:%f b:%f\n",
				// p1.getX(),p1.getY(),p2.getX(), p2.getY(), linearEquation.getK(),
				// linearEquation.getB());
				// System.out.println("want: "+sdf.format(calendar.getTime()));
				// System.out.println("value: " +
				// Double.valueOf(df.format(linearEquation.getY(calendar.getTime().getTime()))));
				// }
				calendar.add(Calendar.MINUTE, dT);
			}
			currentIndex++;
		}

		// 处理最后一天的数据
		if (endDate.compareTo(tempLastDate) >= 0) {
			do {
				rsltHydList.add(new StationDateData(tempLastData.getStationName(), sdf.format(calendar.getTime()),
						Double.valueOf(df.format(tempLastData.getValue()))));
				calendar.add(Calendar.MINUTE, dT);
			} while (calendar.getTime().compareTo(endDate) <= 0);
		}

		return rsltHydList;

	}

	/**
	 * 
	 * @param hydDataList
	 * @param deltaT
	 *            单位为：minute
	 * @return
	 */

	public static FourierSeriesInput hydToFsi(List<StationDateData> hydDataList, double deltaT) {

		double T = deltaT * (hydDataList.size() - 1);
		int seriesCount = hydDataList.size() / 2;

		FourierSeriesInput fsi = hydToFsi(hydDataList, deltaT, seriesCount, T, "defalutFsi");
		return fsi;
	}

	public static FourierSeriesInput hydToFsi(List<StationDateData> hydDataList, Double deltaT, int seriesCount,
			double T, String name) {
		FourierSeriesInput fsi = new FourierSeriesInput();
		Double[] hydArray = hydDataList.stream().map((StationDateData hydData) -> {
			return hydData.getValue();
		}).toArray(Double[]::new);

		fsi.setF(hydArray);
		fsi.setDeltaT(deltaT);
		fsi.setSeriesCount(seriesCount);
		fsi.setT(T);
		fsi.setName(name);
		return fsi;
	}

	/**
	 * 
	 * @param rawHydDataList
	 * @param interval
	 * @param divCount
	 * @param correctRslt
	 * @return
	 * @throws ParseException
	 */
	public static List<StationDateData> doProportionalInterpolation(List<StationDateData> rawHydDataList, int interval,
			int divCount, boolean correctRslt) throws ParseException {
		List<StationDateData> rsltHydList = new ArrayList<>();
		if (rawHydDataList == null || rawHydDataList.size() < 2) {
			System.out.println("input hyd list can not be null or too short.");
			return rsltHydList;
		}

		FourierSeriesInput fsi = hydToFsi(rawHydDataList, interval);
		FourierSeriesHelper fsh = new FourierSeriesHelper(fsi);
		SimpleDateFormat sdf = ConstantHelper.getDefaultFormat();
		String stationName = rawHydDataList.get(0).getStationName();

		double[] fsCalData = fsh.getFtCalByIndex();

		double e, e1, e2, h1, tempHyd, d1, d2 = 0;

		long secInterVal = Math.round((interval * 1.0 / divCount) * 60);
		int T = interval * (rawHydDataList.size() - 1);
		int i, j, t1 = T / 2, t0 = 0;
		Calendar calendar = DateUtil.Date2Calendar(sdf.parse(rawHydDataList.get(0).getDate()));

		// 后续注意验证当流量为0时，这样处理是否合理
		for (i = 1; i < rawHydDataList.size(); i++) {
			d1 = rawHydDataList.get(i - 1).getValue();
			d2 = rawHydDataList.get(i).getValue();

			// e=实测值/计算值
			e1 = (fsCalData[i - 1] != 0.0 ? d1 / fsCalData[i - 1] : 1.0);
			e2 = (fsCalData[i] != 0.0 ? d2 / fsCalData[i] : 1.0);

			// 当前时刻值
			t0 = -t1 + (i - 1) * interval;

			// 起始点，使用第一个值d1
			if (correctRslt) {
				rsltHydList.add(new StationDateData(stationName, sdf.format(calendar.getTime()), d1));
			} else {
				rsltHydList
						.add(new StationDateData(stationName, sdf.format(calendar.getTime()), fsh.getFtCalByTime(t0)));
			}

			calendar.add(Calendar.SECOND, (int) secInterVal);
			for (j = 1; j < divCount; j++) {

				// 插值点时刻值
				t0 += interval * 1.0 / divCount;

				// 得到插值点值
				h1 = fsh.getFtCalByTime(t0);

				// 该点所占比例（线性）
				e = e1 + (e2 - e1) * j / divCount;

				// 按两端值所得比例进行计算
				tempHyd = h1 * e;
				if (correctRslt) {
					rsltHydList.add(new StationDateData(stationName, sdf.format(calendar.getTime()), tempHyd));
				} else {
					rsltHydList.add(new StationDateData(stationName, sdf.format(calendar.getTime()), h1));
				}

				calendar.add(Calendar.SECOND, (int) secInterVal);
			}
		}

		// 结束点,使用第二个实测值d2
		if (correctRslt) {
			rsltHydList.add(new StationDateData(stationName, sdf.format(calendar.getTime()), d2));
		} else {
			t0 += interval * 1.0 / divCount;
			rsltHydList.add(new StationDateData(stationName, sdf.format(calendar.getTime()), fsh.getFtCalByTime(t0)));
		}

		calendar.add(Calendar.SECOND, (int) secInterVal);
		return rsltHydList;
	}

	/**
	 * 细分插值 结合傅里叶级数所得值与原值，两两求算比例，再按比例进行细化插值。
	 * 
	 * @param rawStationDateData
	 * @param interval
	 *            minute
	 * @param divCount
	 * @return
	 * @throws ParseException
	 */
	public static List<StationDateData> doProportionalInterpolation(List<StationDateData> rawHydDataList, int interval,
			int divCount) throws ParseException {
		return doProportionalInterpolation(rawHydDataList, interval, divCount, true);
	}

	public static List<StationDateData> getExtremumTide_V2(List<StationDateData> dataList) throws ParseException {
		List<StationDateData> rsltList = new ArrayList<>();

		int i;
		int minIndex = 0, maxIndex = 0, tempMinIndex, tempMaxIndex;
		int state = 0; // -1表示↓，0表示初始值，1表示↑
		double minVal = Double.MAX_VALUE, maxVal = Double.MIN_VALUE;
		int len = dataList.size();

		if (len < 2) {
			throw new RuntimeException(" data size must be >= 2");
		}

		if (len < 5) {
			tempMinIndex = getMinValIndex(dataList);
			tempMaxIndex = getMaxValIndex(dataList);
			rsltList.add(dataList.get(tempMinIndex).clone());
			rsltList.add(dataList.get(tempMaxIndex).clone());
			return rsltList;
		}

		SimpleDateFormat sdf = ConstantHelper.getDateFormat();
		long nh = 1000 * 60 * 60;
		int interval = 5;
		double dtMax = 1.5;
		double dt = 0.0;

		// 根据走势，当走势发生变化时，记录当前结果，并赋值极小值或极大值
		for (i = 0; i + interval < len; i++) {
			tempMinIndex = getMinValIndex(dataList, i, i + interval);
			tempMaxIndex = getMaxValIndex(dataList, i, i + interval);

			if (tempMinIndex == i && tempMaxIndex == i + interval - 1) {

				// 上升
				if (state == 0) {
					state = 1;
					continue;
				}

				if (state == -1) {
					// 下转上，记录极小值

					rsltList.add(dataList.get(minIndex).clone());
					minVal = Double.MAX_VALUE;
					state = 1;
				}
			} else if (tempMaxIndex == i && tempMinIndex == i + interval - 1) {
				// 下降
				if (state == 0) {
					state = -1;
					continue;
				}

				if (state == 1) {
					// 上转下，记录极大值

					rsltList.add(dataList.get(maxIndex).clone());
					maxVal = Double.MIN_VALUE;
					state = -1;
				}
			} else {
				// 更新极小值或者极大值
				if (dataList.get(tempMinIndex).getValue() < minVal) {
					minIndex = tempMinIndex;
					minVal = dataList.get(tempMinIndex).getValue();
				}

				if (dataList.get(tempMaxIndex).getValue() > maxVal) {
					maxIndex = tempMaxIndex;
					maxVal = dataList.get(tempMaxIndex).getValue();
				}
			}

		}

		return rsltList;
	}

	@Deprecated
	public static List<StationDateData> getExtremumTide(List<StationDateData> dataList) throws ParseException {

		List<StationDateData> rsltList = new ArrayList<>();

		int i;
		int minIndex = 0, maxIndex = 0, tempMinIndex, tempMaxIndex;
		int state = -1;
		int len = dataList.size();

		if (len < 2) {
			throw new RuntimeException(" data size must be >= 2");
		}

		if (len < 5) {
			tempMinIndex = getMinValIndex(dataList);
			tempMaxIndex = getMaxValIndex(dataList);
			rsltList.add(dataList.get(tempMinIndex).clone());
			rsltList.add(dataList.get(tempMaxIndex).clone());
			return rsltList;
		}

		SimpleDateFormat sdf = ConstantHelper.getDateFormat();
		long nh = 1000 * 60 * 60;
		int interval = 5;
		double dtMax = 1.5;
		double dt = 0.0;
		for (i = 0; i + interval < len; i++) {
			if (i == 26) {
				System.out.println();
			}
			tempMinIndex = getMinValIndex(dataList, i, i + interval);
			tempMaxIndex = getMaxValIndex(dataList, i, i + interval);
			if (tempMinIndex > i && tempMinIndex < i + interval - 1) {
				if (state != -1 && state == 1) {

					if (rsltList.size() > 0) {
						// 看是否相隔太近，可能是异常值
						dt = (sdf.parse(dataList.get(maxIndex).getDate()).getTime()
								- sdf.parse(rsltList.get(rsltList.size() - 1).getDate()).getTime()) / nh;
						if (dt > dtMax) {
							// 保存最大值
							rsltList.add(dataList.get(maxIndex).clone());
						}
					} else {
						// 保存最大值
						rsltList.add(dataList.get(maxIndex).clone());
						state = 0;
					}

				}
				// 找到当前极小值
				if (state != 0) {
					minIndex = tempMinIndex;
				} else if (state == 0 && dataList.get(minIndex).getValue() > dataList.get(tempMinIndex).getValue()) {
					minIndex = tempMinIndex;
				}

			}

			if (tempMaxIndex > i && tempMaxIndex < i + interval - 1) {
				if (state != -1 && state == 0) {
					if (rsltList.size() > 0) {
						// 看是否相隔太近，可能是异常值
						dt = (sdf.parse(dataList.get(minIndex).getDate()).getTime()
								- sdf.parse(rsltList.get(rsltList.size() - 1).getDate()).getTime()) / nh;
						if (dt > dtMax) {
							// 保存最小值
							rsltList.add(dataList.get(minIndex).clone());
						}
					} else {
						// 保存最小值
						rsltList.add(dataList.get(minIndex).clone());
					}

				}
				// 找到当前极大值
				if (state != 1) {
					maxIndex = tempMaxIndex;
				} else if (state == 1 && dataList.get(maxIndex).getValue() < dataList.get(tempMaxIndex).getValue()) {
					maxIndex = tempMaxIndex;
				}
				state = 1;
			}
		}
		if (state == 1) {

			if (rsltList.size() > 0) {
				// 看是否相隔太近，可能是异常值
				dt = (sdf.parse(dataList.get(maxIndex).getDate()).getTime()
						- sdf.parse(rsltList.get(rsltList.size() - 1).getDate()).getTime()) / nh;
				if (dt > dtMax) {
					// 保存最大值
					rsltList.add(dataList.get(maxIndex).clone());
				}
			} else {
				// 保存最大值
				rsltList.add(dataList.get(maxIndex).clone());
			}
		} else {

			if (rsltList.size() > 0) {
				// 看是否相隔太近，可能是异常值
				dt = (sdf.parse(dataList.get(minIndex).getDate()).getTime()
						- sdf.parse(rsltList.get(rsltList.size() - 1).getDate()).getTime()) / nh;
				if (dt > dtMax) {
					// 保存最小值
					rsltList.add(dataList.get(minIndex).clone());
				}
			} else {
				// 保存最小值
				rsltList.add(dataList.get(minIndex).clone());
			}

		}

		return rsltList;
	}

	public static int getMinValIndex(List<StationDateData> dataList) {
		return getMinValIndex(dataList, 0, dataList.size());
	}

	public static int getMinValIndex(List<StationDateData> dataList, int start, int end) {
		return getMinValIndex(getDataArrFromList(dataList), start, end);
	}

	public static int getMinValIndex(double[] dataArr, int start, int end) {
		double min = Double.MAX_VALUE;
		int minIndex = 0;
		int len = dataArr.length;
		if (end >= len) {
			throw new RuntimeException("end is more than dataList length");
		}
		for (int i = start; i < end; i++) {
			if (min >= dataArr[i]) {
				minIndex = i;
				min = dataArr[i];
			}
		}
		return minIndex;
	}

	public static int getMaxValIndex(List<StationDateData> dataList) {
		return getMaxValIndex(dataList, 0, dataList.size());
	}

	public static int getMaxValIndex(List<StationDateData> dataList, int start, int end) {
		return getMaxValIndex(getDataArrFromList(dataList), start, end);
	}

	public static int getMaxValIndex(double[] dataArr, int start, int end) {
		double max = Double.MIN_VALUE;
		int maxIndex = 0;
		int len = dataArr.length;
		if (end >= len) {
			throw new RuntimeException("end is more than dataList length");
		}
		for (int i = start; i < end; i++) {
			if (max <= dataArr[i]) {
				maxIndex = i;
				max = dataArr[i];
			}
		}
		return maxIndex;
	}

	public static double[] hydToDoubleList(List<StationDateData> rawHydDataList) {
		return rawHydDataList.parallelStream().mapToDouble(new ToDoubleFunction<StationDateData>() {
			@Override
			public double applyAsDouble(StationDateData value) {
				return value.getValue();
			}
		}).toArray();
	}

	/**
	 * 不好用
	 * 
	 * @param dataList
	 * @return
	 * @throws ParseException
	 */
	@Deprecated
	public static List<StationDateData> highLowTideInterpolation(List<StationDateData> dataList) throws ParseException {
		FourierSeriesNotEqual fsn = new FourierSeriesNotEqual(dataList);
		double t = 0.0, tempData = 0.0;
		List<StationDateData> rsltList = new ArrayList<>();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		Calendar startTime = DateUtil.Date2Calendar(sdf.parse("2003/01/01 00:00:00"));
		System.out.println(sdf.format(startTime.getTime()));
		for (int i = 0; i < 24 * 10; i++) {
			t = i;
			tempData = fsn.getFtCalByTime(t);
			startTime.add(Calendar.HOUR, 1);

			rsltList.add(new StationDateData(null, sdf.format(startTime.getTime()), tempData));
		}
		return rsltList;
	}

	/**
	 * 正弦波插值
	 * 
	 * @param dataList
	 * @param dt
	 *            分钟 int型
	 * @return
	 * @throws ParseException
	 */
	public static List<StationDateData> highLowTideInterpolation_V2(List<StationDateData> dataList, int dt)
			throws ParseException {
		double t = 0.0, tempData = 0.0, x1, x2, v1, v2;
		long nh = 60 * 60 * 1000;
		List<StationDateData> rsltList = new ArrayList<>();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
		DecimalFormat df = new DecimalFormat("#.####");
		Calendar startTime = DateUtil.Date2Calendar(sdf.parse(dataList.get(0).getDate()));
		System.out.println(sdf.format(startTime.getTime()));

		SinInterpolation SI = new SinInterpolation();

		for (int i = 1; i < dataList.size(); i++) {
			x1 = sdf.parse(dataList.get(i - 1).getDate()).getTime() / nh;
			x2 = sdf.parse(dataList.get(i).getDate()).getTime() / nh;
			v1 = dataList.get(i - 1).getValue();
			v2 = dataList.get(i).getValue();

			SI.setParams(x1, v1, x2, v2);
			t = startTime.getTimeInMillis() / nh;
			while (t >= x1 && t <= x2) {
				tempData = SI.getValue(t);
				// System.out.println(tempData);

				rsltList.add(new StationDateData(null, sdf.format(DateUtil.Calendar2Date(startTime)),
						Double.valueOf(df.format(tempData))));
				startTime.add(Calendar.MINUTE, dt);

				t = startTime.getTimeInMillis() * 1.0f / nh;
			}
		}
		return rsltList;
	}

	public static List<StationDateData> fluxFilter(List<StationDateData> fluxList, int interval) {
		int i, j, count = 0, firstIndex = 0, n = fluxList.size();
		double avg = 0.0, val;
		List<StationDateData> avgList = new ArrayList<>();
		for (i = 0; i < interval; i++) {
			avg += (fluxList.get(i).getValue() / interval);
		}

		for (i = 0; i < n - interval; i++) {
			firstIndex = i;
			for (j = i; j < i + interval; j++) {
				val = fluxList.get(j).getValue();

				if (Math.abs((val - avg) / avg) > 0.05) {
					break;
				}
			}

			// 结果满足条件
			if (j - i == interval) {
				System.out.println(fluxList.get(firstIndex).getValue());
				avgList.add(fluxList.get(firstIndex));
				count++;
			}

			// 减去第一个
			val = fluxList.get(firstIndex).getValue();
			avg -= (val / interval);

			// 加上下一个
			if (i + interval < n) {
				val = fluxList.get(i + interval).getValue();
				avg += (val / interval);
			}

		}
		System.out.println("total: " + count);
		return avgList;
	}

	/**
	 * 分别获取实际值与预测值的高低潮，以实测值高低潮时间为准
	 * 
	 * @throws ParseException
	 * @throws IOException
	 */
	public static void higgLowCompare(List<StationDateData> dataList, double[] preDataArr, Path outputPath)
			throws ParseException, IOException {
		// 极值比较输出
		List<StationDateData> dataListRslt = getExtremumTide_V2(dataList);

		List<StationDateData> preListRslt = getExtremumTide_V2(replaceListData(dataList, preDataArr));

		writeToFile(dataListRslt,
				Paths.get("E:\\Kuner\\BYLW\\Jworkspace\\saltyCode\\testify\\mid\\bm\\baimao\\raw.csv"));
		writeToFile(preListRslt,
				Paths.get("E:\\Kuner\\BYLW\\Jworkspace\\saltyCode\\testify\\mid\\bm\\baimao\\pre.csv"));

		// HarmonicHelper hHepler = new HarmonicHelper();
		// hHepler.saveToFile(dataListRslt, getDataArrFromList(preListRslt),
		// outputPath);
	}

	public static List<StationDateData> replaceListData(List<StationDateData> dataList, double[] preDataArr) {
		if (dataList.size() != preDataArr.length) {
			return null;
		}

		List<StationDateData> rsltList = new ArrayList<>();
		StationDateData sData;
		for (int i = 0; i < dataList.size(); i++) {
			sData = dataList.get(i);
			rsltList.add(new StationDateData(sData.getStationName(), sData.getDate(), preDataArr[i]));
		}
		return rsltList;
	}

	public static double[] getDataArrFromList(List<StationDateData> dataList) {
		double[] rsltArr;
		int len = dataList.size();
		rsltArr = new double[len];

		for (int i = 0; i < len; i++) {

			rsltArr[i] = dataList.get(i).getValue();

		}
		return rsltArr;
	}

}
